<?php
/*
* 基本加载入口，命名空间设置，全局公共类加载，全局公共函数
 */
define('LIB_PATH',__DIR__.'/lib/');
define('MOD_PATH',__DIR__.'/mod/');
define('FRAME_ROOT',__DIR__.'/');
define('ADM_ENCRYPT_KEY', 'WhatAFuck1ngDay!ha?');

require LIB_PATH.'Loader.php';
\Lib\Loader::setRootNS('Lib',LIB_PATH);
\Lib\Loader::setRootNS('Mod',MOD_PATH);

// 注册自动加载函数
spl_autoload_register('\\Lib\Loader::autoload');
// 设置时区
date_default_timezone_set('PRC');

/**
* 获取$_GET参数
* @param String $key
* @param Mix $default
* @param String $funs
* @return Mix
*/
function get($key,$default='',$funs=''){
  $val = _get_post($key,$funs,'get');
  return $val ? $val : $default;
}

/**
* 获取$_POST参数
* @param String $key
* @param Mix $default
* @param String $funs
* @return Mix
*/
function post($key,$default='',$funs=''){
  $val = _get_post($key,$funs,'post');
  return $val ? $val : $default;
}

/**
* 获取$_REQUEST参数
* @param String $key
* @param Mix $default
* @param String $funs
* @return Mix
*/
function request($key,$default='',$funs=''){
  $val = _get_post($key,$funs,'get');
  if(empty($val)){
    $val = _get_post($key,$funs,'post');
  }
  return $val ? $val : $default;
}

/**
* get,post,request的处理函数
* @param String $key
* @param String $funs
* @param String $method
* @return Mix
*/
function _get_post($key,$funs='',$method='get'){
  $arr = explode('.',$key);
  if($arr>1){
    $key = array_shift($arr);
    $key2 = array_shift($arr);
  }
  $data = strtolower($method) == 'get' ? $_GET : (strtolower($method) == 'post' ? $_POST : array());
  $val = isset($data[$key]) ? $data[$key] : null;
  if(isset($key2) && !empty($key2)){
    (isset($val[$key2]) && $val = $val[$key2]) || $val = null;
  }
  
  if(empty($val)) return false;
  if($funs){
    if(!is_array($funs)){
      $funs = explode(',',$funs);
      foreach($funs as $fun){
        $val = $fun($val);
      }
    }else{
      $val = $funs[0]->$funs[1]($val);
    }
  }
  return $val;
}

/**
* 添加一个动作*
* @param String $type
* @param Mix $handler
* @param Int $weight
* @return Bool
*/
function add_action($type,$handler,$weight=1){
	global $php;
	$php->plugins[$type][$weight][] = $handler;
	return true;
}

/**
* 执行一批动作
* @param String $type
* @return void
*/
function apply_action($type){
  global $php;
  $argvs = func_get_args();
  array_shift($argvs);
  if(isset($php->plugins[$type]) && !empty($php->plugins[$type])){
    $actions = $php->plugins[$type];
    ksort($actions);
    foreach($actions as $action){
      foreach($action as $the_action){
        call_user_func_array($the_action, $argvs);
      }
    }
  }
}

/**
* 输出调试信息
* @return void
*/
function debug(){
	$html = '<pre>';
    $vars = func_get_args();
    foreach($vars as $var) $html.=print_r($var,true);
    $html .= '</pre>';
    // $php->error('debug',$html);
    throw new \Exception($html, 1);
}

/**
* 抛出错误信息和代码
* @access public
* @param String $msg
* @param Int $code
* @return void
*/
function error($msg,$code=1){
	throw new \Exception($msg, $code);
}

/**
* 设置HTTP头
* @param String $key
* @param String $value
* @return void
*/
function set_header($key,$value){
  global $php;
  $php->header($key,$value);
}

/**
* 根据传入的参数获取带http的二级域名，参数为空则输出顶级域名
* @param String $dom_name
* @return String
*/
function dom($dom_name=null){
    if(isset($_SERVER['SERVER_PROTOCOL'])){
      $sch = strpos($_SERVER['SERVER_PROTOCOL'],'https') !==false ? 'https://' : 'http://';
    }else{
      $sch = 'http://';
    }
    
    if(strpos($_SERVER['HTTP_HOST'],":")!==false)
        list($host,$port) = explode(":",$_SERVER['HTTP_HOST']);
    else
        $host = $_SERVER['HTTP_HOST'];
    if(is_ip($host)){
        return $sch.$host.(isset($port) && !empty($port) ? ':'.$port : '');
    }
    $arr = explode('.',$host);
    $dom = array();
    for($i=count($arr)-1;$i>=0;$i--){
        if(in_array($arr[$i],array('com','cn','net','me','info','gov','org'))){
            $dom[] = array_pop($arr);
        }
    }
    $dom[] = array_pop($arr);
    while(count($arr)>1){
        $dom[] = array_pop($arr);
    }
    $dom = array_reverse($dom);
    $domain = join('.',$dom);
    if(empty($dom_name)){
        return $sch.$domain;
    }else{
        return $sch.$dom_name.'.'.$domain;  
    }
}

/**
* 获取网站根链接，无论任何情况下，都输出例如：http://www.59pi.com:port的地址
* @access public
* @param
* @return
*/
function site_url(){
  if(isset($_SERVER['SERVER_PROTOCOL'])){
    $sch = strpos($_SERVER['SERVER_PROTOCOL'],'https') !==false ? 'https://' : 'http://';
  }else{
    $sch = 'http://';
  }
  
  if(strpos($_SERVER['HTTP_HOST'],":")!==false)
      list($host,$port) = explode(":",$_SERVER['HTTP_HOST']);
  else
      $host = $_SERVER['HTTP_HOST'];
  return $sch.$host.(isset($port) && !empty($port) ? ':'.$port : '');
}

/**
* 获取当前浏览器访问的链接
* @return String
*/
function cur_url(){
  if(isset($_SERVER['SERVER_PROTOCOL'])){
    $sch = strpos($_SERVER['SERVER_PROTOCOL'],'https') !==false ? 'https://' : 'http://';
  }else{
    $sch = 'http://';
  }
  
  if(strpos($_SERVER['HTTP_HOST'],":")!==false)
      list($host,$port) = explode(":",$_SERVER['HTTP_HOST']);
  else
      $host = $_SERVER['HTTP_HOST'];
  $path = $_SERVER['REQUEST_URI'];
  $url = $sch.$host.(isset($port) && !empty($port) ? ':'.$port : '').$path;
  return $url;
}

/**
* 操作COOKIE
* 只传入$name时，获取名称为$name的cookie
* 传入$name但$value为null时，删除$name的cookie
* 同时传入$name和$value，设置名称为$name，值为$value的cookie
* @param String $name
* @param String $value
* @param Int $expires
* @param String $path
* @param String $domain
* @return Mix
*/
function cookie($name,$value='',$expires=0,$path='/',$domain=''){
	global $php;
	empty($domain) && $domain = parse_url(dom())['host'];
	if($value===''){
		return isset($_COOKIE[$name]) ? $_COOKIE[$name] : false;
	}elseif($value===null){
		$php->setCookie($name,'',-3600,$path,$domain);
	}else{
		$php->setCookie($name,$value,$expires,$path,$domain);
	}
}

/**
* 操作session
* 只传入$name时，获取名称为$name的session
* 传入$name但$value为null时，删除$name的session
* 同时传入$name和$value，设置名称为$name，值为$value的session
* $name为@id，表示获取当前session的ID
* @param String $name
* @param Mix $value
* @return Mix
*/
function session($name,$value=''){
	global $php;
  if($name{0} == '@'){
    switch(substr($name, 1)){
      case 'id':
        return $php->session->getSessionId();
        break;
      default :
        return false;
      break;
    }
  }
  $prefix = isset($php->config['session']['prefix']) ? $php->config['session']['prefix'] : '';
	if($name===null){
		return $php->session->delete();
	}
  $name = $prefix.$name;
  if($value===''){
		return isset($_SESSION[$name]) ? $_SESSION[$name] : false;
	}elseif($value===null){
		unset($_SESSION[$name]);
	}else{
		$_SESSION[$name] = $value;
	}
}

/**
* 操作储存系统
* $file_path为@开头，并且后面是一个文件的绝对路径时，表示前这个文件上传到储存系统，此时$content可当作$params
* $file_path为储存系统的文件路径，其它参数为空时，表示获取这个文件内容
* $file_path为储存系统的文件路径 $content为null时，表示删除这个文件
* $file_path为储存系统的文件路径，$content为字符串，表示将$content储存到$file_path的文件内
* $params为一个一维数组，支持的参数有：path:文件在储存系统中的位置,
* @param String $file_path
* @param String $content
* @param Array $params
* @return Mix
*/
function storage($file_path,$content = '' , $params = array()){
  global $php;
  if($file_path{0} == '@'){
    return $php->storage->save($file_path,$params);
  }elseif($content===''){
    return $php->storage->get($file_path);
  }elseif($content===null){
    return $php->storage->delete($file_path);
  }else{
    if(is_string($content))
      return $php->storage->save($file_path,$content,$params);
    else
      throw new \Exception("Content must be string", 200);
  }
}

/**
* 操作缓存
* 只传入$key表示获得key为$key的缓存内容
* 传入$key和$value表示设置key为$key的，值为$value的缓存
* 传入$key，$value为null表示删除$key的缓存
* @param String $key 缓存key
* @param Mix $value 内容
* @param Int $expires 过期时间
* @return Mix
*/
function cache($key,$value='',$expires=0){
	global $php;
	if($key===null){
		return $php->cache->clean();
	}elseif($value===''){
		return $php->cache->get($key);
	}elseif($value===null){
		return $php->cache->delete($key);
	}else{
		return $php->cache->set($key,$value,$expires);
	}
}

/**
* 操作配置系统
* config('name')表示获取名称为name的配置项
* config('name',null)表示删除名称为name的配置项
* config('name','value')表示设置名称为name，值为value的配置项
* @param String $name 配置项名称
* @param Mix $value 配置项内容
* @return Mix
*/
function config($name,$value=''){
  static $kvdb;
  empty($kvdb) && $kvdb = new \Lib\Kvdb('adm_system');
  if($value===''){
    return $kvdb->get($name);
  }elseif($value===null){
    return $kvdb->delete($name);
  }else{
    return $kvdb->set($name,$value);
  }
}

/**
* 获得一个数据模型
* model('#TableName')表示获得服务器内置的数据模型
* model('TableName')表示获得用户自定义的数据模型
* 参数$prefix表示表前缀，如：59pi_
* @param String $mod_name 数据表名
* @param String $prefix 表前缀
* @return Object
*/
function model($mod_name='',$prefix=''){
  return \Lib\Loader::loadModel($mod_name,$prefix);
}

/**
 * curl封装
 * @param string $url 资源地址   
 * @param string $method 提交方法，默认为get
 * @param array $postfields  post表单字段        
 * @return string
 */
function curl($url,$method = 'GET',$postFields = array()){
  $ch = curl_init();
  curl_setopt($ch,CURLOPT_URL,$url);
  curl_setopt($ch,CURLOPT_FAILONERROR,false);
  curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  curl_setopt($ch,CURLOPT_REFERER,$url);
  curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0 tester');
  curl_setopt($ch, CURLOPT_HEADER, 0);
  //超时时间
  curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,90);
  curl_setopt($ch, CURLOPT_TIMEOUT, 90);
  
  // https 请求
  if(strlen($url) >5 &&strtolower(substr($url,0,5)) =="https"){
    curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
    curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);
  }
  
  if(is_array($postFields) &&0 <count($postFields)){
    $postBodyString = "";
    $postMultipart = false;
    foreach($postFields as $k=>$v){
      if("@" !=substr($v,0,1))      // 判断是不是文件上传
      {
        $postBodyString .= "$k=" .urlencode($v) ."&";
      }else      // 文件上传用multipart/form-data，否则用www-form-urlencoded
      {
        $postMultipart = true;
      }
    }
    unset($k,$v);
    curl_setopt($ch,CURLOPT_POST,strtolower($method)=='post' || $postMultipart===true);
    if($postMultipart){
      curl_setopt($ch,CURLOPT_POSTFIELDS,$postFields);
    }else{
      curl_setopt($ch,CURLOPT_POSTFIELDS,substr($postBodyString,0, -1));
    }
  }elseif(is_string($postFields) && $postFields){
      curl_setopt($ch,CURLOPT_POSTFIELDS,$postFields);
  }
  $reponse = curl_exec($ch);
  
  if(curl_errno($ch)){
    curl_close($ch);
    throw new \Exception(curl_error($ch).'<br>URL:'.$url,0);
  }else{
    $httpStatusCode = curl_getinfo($ch,CURLINFO_HTTP_CODE);
    if(200 !==$httpStatusCode){
      curl_close($ch);
      throw new \Exception($reponse.'<br>URL:'.$url,$httpStatusCode);
    }
  }
  curl_close($ch);
  return $reponse;
}

/**
* 输出运行时间
* @param String $type 如：开始用 'start' ，结束用 'end'
* @return
*/
function _time($type){
	static $types = [];
	$types[$type] = microtime(true);
	echo $type.":".$types[$type].'<br>'.PHP_EOL;
	$times = array_values($types);
	if(count($times)>1){
		echo 'runTime:'.($times[1] - $times[0]).'<br>'.PHP_EOL;
		$types = [];
	}
}

/**
* 判断是否ajax请求
* @return Bool
*/
function is_ajax(){
	return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] || isset($_GET['ajax']);
}

/**
* 判断是否post请求
* @return Bool
*/
function is_post(){
	return !empty($_POST) || !empty($_FILES);
}

/**
* 判断是否get请求
* @return Bool
*/
function is_get(){
	return !empty($_GET);
}

/**
* 获取文件的mime类型
* @param String $path 文件的绝对路径
* @return Array [后缀,mime类型]
*/
function get_mime($path) {
    $mimes = \Lib\Mimes::mimes();
    $file_info = exec('file -ib '.escapeshellarg($path));
    //文件存在
    $mime = '';
    $type = 'unknown';
    if(strpos($file_info,'ERROR')===false){
      $mime = explode(';', $file_info)[0];
      $type = $mimes[$mime];
    }
    return [$type,$mime];
}

/**
* 302跳转
* @param String $url
* @return void
*/
function redirect($url){
  global $php;
  $php->http302($url);
}

/**
* 将输入转换为绝对整数
* @param numeric $num
* @return Int
*/
function absint($num){
  return abs(intval($num));
}

/**
* 处理长整数
* @param numeric $num
* @return numeric
*/
function longint($num){
  return sprintf("%.0f",$num);
}


/**
* 获取cpu的空闲百分比 
* @return String
*/
function get_cpufree(){ 
    $cmd =  "top -n 1 -b -d 0.1 | grep 'Cpu'";//调用top命令和grep命令 
    $lastline = exec($cmd,$output); 
    
    preg_match('/(\S+)%id/',$lastline, $matches);//正则表达式获取cpu空闲百分比 
    $cpufree = $matches[1]; 
    return $cpufree; 
} 

/**
* 获取内存空闲百分比 
* @return String
*/
function get_memfree(){ 
    $cmd =  'free -m';//调用free命令 
    exec($cmd,$output); 
    preg_match('/Mem:\s*(\d+)/',$output[1], $matches); 
    $memtotal = $matches[1]; 
    preg_match('/(\d+)$/',$output[2], $matches); 
    $memfree = sprintf('%0.2f',$matches[1]*100.0/$memtotal); 
    
    return $memfree; 
} 
    
/**
* 获取某个程序当前的进程数
* @return String
*/ 
function get_proc_count($name){ 
    $cmd =  "ps -e";//调用ps命令 
    $output = shell_exec($cmd); 
    
    $result = substr_count($output, ' '.$name); 
    return $result; 
}

/**
* 移动文件到指定位置
* @param String $source 源文件路径
* @param String $dest 目录路径
* @return void
*/
function move_file($source,$dest){
  exec("mv {$source} {$dest}");
}

/**
* 获取referer地址
* @param String $url
* @return String
*/
function referer($url=null){
  if(!empty($url)){
    session('adm_referer',$url);
    return $url;
  }
  if($url=session('adm_referer')){
    session('adm_referer',null);
    return $url;
  }elseif(isset($_SERVER['HTTP_REFERER'])){
    return $_SERVER['HTTP_REFERER'];
  }
  return '/index';
}

/**
 * 字符串截取，支持中文和其他编码
 * @param string $str 需要转换的字符串
 * @param string $start 开始位置
 * @param string $length 截取长度
 * @param string $charset 编码格式
 * @param string $suffix 截断显示字符
 * @return string
 */
function msubstr($str, $start=0, $length, $charset="utf-8", $suffix=false) {
    if(function_exists("mb_substr"))
        $slice = mb_substr($str, $start, $length, $charset);
    elseif(function_exists('iconv_substr')) {
        $slice = iconv_substr($str,$start,$length,$charset);
        if(false === $slice) {
            $slice = '';
        }
    }else{
        $re['utf-8']   = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
        $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
        $re['gbk']    = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
        $re['big5']   = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
        preg_match_all($re[$charset], $str, $match);
        $slice = join("",array_slice($match[0], $start, $length));
    }
    return $suffix ? $slice.'...' : $slice;
}

/**
* 验证是否EMAIL地址
* @param String $mail 待验证的邮箱地址
* @return bool
*/
function is_mail($mail){
  return filter_var($mail,FILTER_VALIDATE_EMAIL);
}

/**
* 验证是否合法的url
* @param string $url
* @return bool
*/
function is_url($url){
  return filter_var($url,FILTER_VALIDATE_URL);
}

/**
* 验证是否QQ号码
* @param numeric $qq
* @return bool
*/
function is_qq($qq){
  $ret = !empty($qq) && preg_match('/\d{5,15}/', $qq);
  return $ret ? $qq : false;
}

/**
* 验证是否合法的手机号码
* @param string $mobile
* @return bool
*/
function is_mobile($mobile){
  $ret = !empty($mobile) && preg_match("/^(?:\+[\d]{2,3})?(?:130|131|132|133|134|135|136|137|138|139|147|150|151|152|153|154|155|156|157|158|159|170|171|172|173|174|175|176|177|178|179|180|181|182|183|184|185|186|187|188|189)[\d]{8}$/",$mobile);
  return $ret ? $mobile : false;
}

/**
* 验证是否合法的电话号码
* @access public
* @param string $phone
* @return bool
*/
function is_phone($phone){
  $ret = !empty($phone) && preg_match('/^[\d]{3,4}\-[1-9][\d]{6,8}$/', $phone);
  return $ret ? $phone : false;
}

/**
* 字符串模糊化
* @param string $str 待模糊化的字符串
* @param int $start 开始位置
* @param int $length 模糊化的字数
* @return string
*/
function fuzzy($str,$start=3,$length=5){
  $str1 = mb_substr($str,0, $start);
  $str2 = str_repeat('*', $length);
  $pos = $start + $length;
  $count = mb_strlen($str);
  $str3 = $pos>=$count ? '' : mb_strcut($str, $pos);
  return $str1.$str2.$str3;
}

/**
* 邮箱地址模糊化
* @param string $email 待模糊化的字符串
* @return string
*/
function fuzzy_email($email){
  if(empty($email) || !is_mail($email)){
    return fuzzy($email,3,4);
  }
  list($account,$domain) = explode('@',$email);
  $account = fuzzy($account,2,4);
  return $account.'@'.$domain;
}

/**
* 实时发送邮件
* @param string $to 收件人
* @param string $subject 邮件标题
* @param string $body 邮件内容
* @param array $attachment 邮件附件
* @return bool
*/
function send_mail($to, $subject = '', $body = '', $attachment = null){
  if(!filter_var($to,FILTER_VALIDATE_EMAIL) || $subject=='' || $body==''){
      return false;
  }
  $mail             = new \Lib\Mailer\Mailer(); //PHPMailer对象
  $mail->CharSet    = 'UTF-8'; //设定邮件编码，默认ISO-8859-1，如果发中文此项必须设置，否则乱
  $mail->SMTPDebug  = 0;                     // 关闭SMTP调试功能
                                             // 1 = errors and messages
                                             // 2 = messages only
  $mail->SetFrom(config('email_addr'), config('email_addr'));

  if(config('email_type')==\Lib\Mailer\Mailer::SMTP){
      $mail->IsSMTP();  // 设定使用SMTP服务
      $mail->SMTPAuth   = true;                  // 启用 SMTP 验证功能
      $mail->Host       = config('email_host');  // SMTP 服务器
      config('email_port')==465 && $mail->SMTPSecure ='ssl'; //是否使用ssl
      $mail->Port       = config('email_port');  // SMTP服务器的端口号
      $mail->Username   = config('email_user');  // SMTP服务器用户名
      $mail->Password   = config('email_pass');  // SMTP服务器密码
      $mail->Timeout      = 30; //超时时间　秒
  }else{
      /* mail */
      $mail->IsMail();
  }
  
  $mail->Subject    = $subject;
  $mail->MsgHTML($body);
  $mail->AddAddress($to);
  if(is_array($attachment)){ // 添加附件
      foreach ($attachment as $file){
          is_file($file) && $mail->AddAttachment($file);
      }
  }
  return $mail->Send() ? true : $mail->ErrorInfo;
}

/**
* 图片x轴翻转，翻转后替换原图片文件
* @param string $img_file 待翻转的图片路径
* @param string $type 图片类型
* @return void
*/
function trun_x($img_file_path,$type='jpeg'){
  switch($type){
    case 'jpeg':
      $create_fun = 'imagecreatefromjpeg';
      $save_fun = 'imagejpeg';
      break;
    case 'gif':
      $create_fun = 'imagecreatefromgif';
      $save_fun = 'imagegif';
      break;
    case 'png':
      $create_fun = 'imagecreatefrompng';
      $save_fun = 'imagepng';
      break;
    default :
      $create_fun = 'imagecreatefromjpeg';
      $save_fun = 'imagejpeg';
      break;
  }
  $resource = $create_fun($img_file_path);
  $w = imagesx($resource);
  $h = imagesy($resource);
  $new = imagecreatetruecolor($w, $h);
  for ($y=0; $y < $h; $y++) { 
    imagecopy($new, $resource, 0 , $h-$y-1, 0, $y, $w, 1);
  }
  $save_fun($new,$img_file_path);
  imagedestroy($resource);
  imagedestroy($new);
}

/**
* 图片y轴翻转，翻转后替换原图片
* @param string $img_file_path 待翻转的图片路径
* @param string $type 图片类型
* @return void
*/
function trun_y($img_file_path,$type='jpeg'){
  switch($type){
    case 'jpeg':
      $create_fun = 'imagecreatefromjpeg';
      $save_fun = 'imagejpeg';
      break;
    case 'gif':
      $create_fun = 'imagecreatefromgif';
      $save_fun = 'imagegif';
      break;
    case 'png':
      $create_fun = 'imagecreatefrompng';
      $save_fun = 'imagepng';
      break;
    default :
      $create_fun = 'imagecreatefromjpeg';
      $save_fun = 'imagejpeg';
      break;
  }
  $resource = $create_fun($img_file_path);
  $w = imagesx($resource);
  $h = imagesy($resource);
  $new = imagecreatetruecolor($w, $h);
  for ($x=0; $x < $w; $x++) { 
    imagecopy($new, $resource , $w-$x-1, 0, $x,0, 1, $h);
  }
  $save_fun($new,$img_file_path);
  imagedestroy($resource);
  imagedestroy($new);
}

/**
* 验证是否合法的身份证号码
* @param string $id_card 身份证号码
* @return bool
*/
function is_id_card($id_card){
  $id_card = strip_tags($id_card);
  if(empty($id_card)){
    return false;
  }
  $id_card = _to18Card($id_card);
  if(strlen($id_card) != 18){ 
    return false;
  }
  $cardBase = substr($id_card, 0, 17); 

  return _getVerifyNum($cardBase) == strtoupper(substr($id_card, 17, 1)) ? $id_card : false;
}

/**
* 格式化15位身份证号码为18位 
* @param string $card 身份证号码
* @return string
*/
function _to18Card($card) { 
  $card = trim($card); 

  if (strlen($card) == 18) { 
      return $card; 
  } 

  if (strlen($card) != 15) { 
      return false; 
  } 

  // 如果身份证顺序码是996 997 998 999，这些是为百岁以上老人的特殊编码 
  if (array_search(substr($card, 12, 3), array('996', '997', '998', '999')) !== false) { 
      $card = substr($card, 0, 6) . '18' . substr($card, 6, 9); 
  } else { 
      $card = substr($card, 0, 6) . '19' . substr($card, 6, 9); 
  } 
  $card = $card . _getVerifyNum($card); 
  return $card; 
} 

/**
* 计算身份证校验码，根据国家标准gb 11643-1999 
* @param string $cardBase 身份证号码
* @return string
*/
function _getVerifyNum($cardBase) { 
    if (strlen($cardBase) != 17) { 
        return false; 
    } 
    // 加权因子 
    $factor = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2); 

    // 校验码对应值 
    $verify_number_list = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'); 

    $checksum = 0; 
    for ($i = 0; $i < strlen($cardBase); $i++) { 
        $checksum += substr($cardBase, $i, 1) * $factor[$i]; 
    } 

    $mod = $checksum % 11; 
    $verify_number = $verify_number_list[$mod]; 

    return $verify_number; 
}

/**
* 验证是否日期时间
* @param string $datetime 待验证的时间日期，格式为：yyyy-MM-dd HH:ii:ss
* @return bool
*/
function is_datetime($datetime){
  if(empty($datetime)){
    return false;
  }
  $arr = explode(' ',$datetime);
  if(!is_date($arr[0])){
    return false;
  }
  if(isset($arr[1]) && !is_time($arr[1])){
    return false;
  }
  return true;
}

/**
* 验证是否合法的日期
* @param string $date 日期，如：2015-01-16
* @return bool
*/
function is_date($date){
  if(empty($date)){
    return false;
  }
  $arr = explode('-',$date,3);
  if($arr<3){
    return false;
  }
  list($year,$month,$day) = $arr;
  if($year<1970 || $year>date('Y')){
    return false;
  }
  if($month<1 || $month>12){
    return false;
  }
  $days = [31,date('Y')%4==0 ? 29 : 28,31,30,31,30,31,31,30,31,30,31];
  if($day<1 || $day>$days[$days[date('m')-1]]){
    return false;
  }
  return true;
}

/**
* 验证是否合法的时间
* @param string $time 时间，如：17:00:00
* @return bool
*/
function is_time($time){
  if(empty($time)){
    return false;
  }
  $arr = explode(':',$time);
  if($arr<3){
    return false;
  }
  list($h,$i,$m) = $arr;
  if($h<0 || $h>23)return false;
  if($i<0 || $i>59)return false;
  if($m<0 || $m>59)return false;
  return true;
}

/**
* 将字符串用逗号分隔成数组
* @param string $string 待转换的数组
* @return array
*/
function string2array($string){
  if(empty($string)) return [];

  return !is_array($string) ? explode(',',$string) : $string;
}

/**
 * 获取客户端IP地址
 * @param integer $type 返回类型 0返回IP地址 1返回IPV4地址数字
 * @return mixed
 */
function get_client_ip($type = 0) {
  $type       =  $type ? 1 : 0;
  static $ip  =   NULL;
  if ($ip !== NULL) return $ip[$type];
  if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
      $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
      $pos    =   array_search('unknown',$arr);
      if(false !== $pos) unset($arr[$pos]);
      $ip     =   trim($arr[0]);
  }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
      $ip     =   $_SERVER['HTTP_CLIENT_IP'];
  }elseif (isset($_SERVER['REMOTE_ADDR'])) {
      $ip     =   $_SERVER['REMOTE_ADDR'];
  }
  // IP地址合法验证
  $long = sprintf("%u",ip2long($ip));
  $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
  return $ip[$type];
}

/**
* JSON格式的数据转换成数组
* @param string $data 待转换的合法的json数据
* @return array
*/
function json_array($data){
  if(empty($data) || !is_string($data)){
    return [];
  }
  $data = json_decode($data);
  if(empty($data))
    return [];
  return get_object_vars_deep($data);
}

/**
 * 递归将对象变成数组
 * @param objecy $objdct          
 * @return array
 */
function get_object_vars_deep($obj){
  if(is_object($obj))
  {
    $obj = get_object_vars($obj);
  }
  if(is_array($obj))
  {
    foreach ($obj as $key => $value)
    {
      $obj[$key] = get_object_vars_deep($value);
    }
  }
  return $obj;
}

/**
* 判断是否合法的IP地址
* @param string $ip 待判断的字符串
* @return bool
*/
function is_ip($ip){
  $long = sprintf("%u",ip2long($ip));
  return !empty($long) && is_numeric($long);
}

/**
* 判断给定的值是否不为空字符串
* @param string $val
* @return bool
*/
function not_empty($val){
  return $val==='' ? false : $val;
}

/**
* 将时间戳转换成日期时间格式
* @param timestamp $timestamp
* @param String $format
* @return String
*/
function datetime($timestamp,$format='Y-m-d H:i:s'){
  if(empty($timestamp)) return '';
  return date($format,$timestamp);
}

/**
* 检查并返回全数字的数组，如果是参数是字符串，则先用逗号分隔成成数组
* @param Mix $arr
* @return Array
*/
function is_num_array($arr){
  if(empty($arr)) return [];
  if(!is_array($arr)){
    $arr = explode(',',$arr);
  }
  foreach($arr as $item){
    if(!is_numeric($item)){
      return false;
    }
  }
  return $arr;
}

/**
* 检查是否正整数
* @param numeric $num
* @return bool
*/
function is_absint($num){
  $int = longint($num);
  return $int == $num && $int>=0;
}

/**
* 将数字转换成2位数的金钱
* @param numeric $num
* @return float
*/
function price($num){
  return sprintf('%0.2f',$num);
}